<?php

namespace app\api\logic;

use app\common\exception\BusinessException;
use app\common\helper\JwtHelper;
use app\common\model\AgentRelation;
use app\common\model\AppConfig;
use app\common\model\MpUser;
use app\common\model\Profession as ProfessionModel;
use app\common\model\User as UserModel;
use app\common\model\UserAgentRecord;
use app\common\model\UserSubscribe;
use app\common\model\UserVip;
use app\common\service\GlobalsVariableService;
use app\common\service\MailService;
use app\common\service\SmsService;
use app\common\service\UserService;
use app\common\service\WxService;
use think\facade\Cache;
use think\facade\Config;

class User
{
    /**
     * getUserInfoById
     * @param int $userId
     * @return array
     * @throws
     */
    public function info(int $userId): array
    {
        $time = time();
        $appId = getAppId();
        $info = app(UserService::class)->getUserById($userId);
        if ($info) {
            $info['is_vip'] = 0;
            $info['has_vip'] = false;
            $info['is_profession_vip'] = false;
            $info['avatar'] = fillUserAvatar($info['avatar']);
            $info['vip_name'] = '普通会员';
            if ($info['profession_id']) {
                // 填充专业信息
                $professionInfo = app(ProfessionModel::class)->getInfo($info['profession_id'], 'name');
                if ($professionInfo) {
                    $info['profession_name'] = $professionInfo['name'];
                }

                // 填充VIP信息
                $vip_info = app(UserVip::class)->getInfo($info['id'], $info['profession_id']);
                if ($vip_info) {
                    $info['is_vip'] = 1;
                    $info['is_profession_vip'] = true;
                    $info['vip_expire_name'] = date('Y-m-d H:i:s', $vip_info['expire']);;
                }
            }

            // 填充VIP列表
            $info['vip_list'] = app(UserVip::class)->getVipList($userId);
            foreach ($info['vip_list'] as $key => $val) {
                // 标记当前用户拥有有效VIP
                if ($val['expire'] > $time) {
                    $info['is_vip'] = 1;
                    $info['has_vip'] = true;
                    $info['vip_name'] = "超级会员";
                }

                // 填充名称
                if ($val['old_name']) {
                    $info['vip_list'][$key]['name'] .= '(原' . $val['old_name'] . ')';
                }

                // 专业层级
                $info['vip_list'][$key]['layer_name'] = '';
                if ($val['layer'] > 0) {
                    $info['vip_list'][$key]['layer_name'] = $val['layer'] == 1 ? '本科' : '专科';
                }

                // 格式化到期时间
                $info['vip_list'][$key]['expire_name'] = date('Y-m-d H:i:s', $val['expire']);
            }
        }

        // 读取用户中心页面配置参数
        $pageConfig = app(AppConfig::class)->getByIdAndType($appId, 'user_center_page_set');
        $info['pageConfig'] = $pageConfig;
        return $info;
    }

    /**
     * update
     * @param array $data
     * @throws
     */
    public function update(array $data)
    {
        // 提取参数
        $userId = $data['userId'];

        // 临时处理
        $field = '*';
        $where = [['id', '=', $userId]];
        $userInfo = app(UserModel::class)->field($field)->where($where)->find();
        if ($userInfo && !$userInfo['unionid']) {
            //throw new BusinessException('您需要在会员中心再次绑定微信,会送积分哦');
        }

        // 授权修改字段
        $allowField = [
            'exam_id',
            'realname',
            'alipay_account',
            'avatar',
            'nickname',
            'profession_id',
            'region_id'
        ];
        foreach ($data as $key => $val) {
            if (!in_array($key, $allowField)) {
                unset($data[$key]);
            }
        }
        $data['update_time'] = time();

        // 查询条件
        $where = ['id' => $userId];

        // 更新数据
        $isUpdate = UserModel::where($where)->update($data);
        if ($isUpdate === false) {
            throw new BusinessException('更新用户信息失败');
        }
    }

    /**
     * register
     * @param array $params
     * @return array
     * @throws BusinessException
     */
    public function register(array $params): array
    {
        // 提取参数
        $code = trim($params['code']);
        $username = trim($params['username']);
        $password = trim($params['password']);
        $appId = GlobalsVariableService::get('appId');

        // 检查验证码
        if (!app(SmsService::class)->checkCode($username, $code)) {
            throw new BusinessException('验证码不正确或已失效');
        }

        // 检查手机号
        if (app(UserService::class)->checkMobileExist($appId, $username)) {
            throw new BusinessException('手机号码已经注册');
        }

        // 新增用户
        $time = time();
        $data = [
            'mobile' => $username,
            'username' => $username,
            'password' => sha1($password),
            'nickname' => hideMobile($username),
            //'agent_id' => $agent_id,
            'avatar' => getRandAvatar(),
            'status' => 1,
            'create_time' => $time,
            'update_time' => $time,
            'app_id' => $appId,
        ];
        $userId = (new UserModel())->insert($data, true);
        if (!$userId) {
            throw new BusinessException('注册失败,请重试');
        }

        // 赠送积分
        app(ScoreActivity::class)->initConfig($appId)->send($userId, 1);

        // 生成token
        $data['token'] = JwtHelper::create($userId, config('mcp.tokenExpire'));
        $data['avatar'] = fillUserAvatar($data['avatar']);

        // 返回
        return $data;
    }

    /**
     * login
     * @param array $params
     * @return array
     * @throws BusinessException
     */
    public function login(array $params): array
    {
        // 提取参数
        $username = $params['username'];
        $password = sha1(trim($params['password']));
        $appId = GlobalsVariableService::get('appId');

        // 查询用户
        $info = app(UserService::class)->getUserByAuth($appId, $username, $password);
        if (!$info) {
            throw new BusinessException('登录账号或密码不正确');
        }
        if ($info['status'] !== 1) {
            throw new BusinessException('当前账号已禁用');
        }

        // 赠送积分
        app(ScoreActivity::class)->initConfig($appId)->send($info['id'], 2);

        // 生成token
        $info['token'] = JwtHelper::create($info['id'], config('mcp.tokenExpire'));
        $info['avatar'] = fillUserAvatar($info['avatar']);

        // 返回
        return $info;
    }

    /**
     * resetPassword
     * @param array $param
     * @throws
     */
    public function resetPassword(array $param)
    {
        // 提取参数
        $time = time();
        $username = $param['username'];
        $password = sha1(trim($param['password']));
        $verifyCode = $param['verifyCode'];
        $appId = GlobalsVariableService::get('appId');

        // 查询信息
        $field = '*';
        $where = [['mobile', '=', $username], ['app_id', '=', $appId]];
        $userInfo = app(UserModel::class)->field($field)->where($where)->find();
        $userInfo = $userInfo ? $userInfo->toArray() : [];
        if (!$userInfo) {
            throw new BusinessException('手机号未注册账号');
        }

        // 检查验证码
        if (!app(SmsService::class)->checkCode($username, $verifyCode)) {
            throw new BusinessException('验证码不正确或已失效');
        }

        // 重置密码
        $where = [['id', '=', $userInfo['id']]];
        $update = [
            'password' => $password,
            'update_time' => $time
        ];
        $isUpdate = (new UserModel())->where($where)->save($update);
        if (!$isUpdate) {
            throw new BusinessException('重置密码失败');
        }
    }

    /**
     * changeMail
     * @param array $params
     * @throws
     */
    public function changeMail(array $params)
    {
        // 提取参数
        $email = $params['email'];
        $action = $params['action'];
        $userId = $params['userId'];
        $verifyCode = $params['verifyCode'];
        $appId = getAppId();

        // 查询用户信息
        $field = 'openid,email,username';
        $info = app(UserModel::class)->where(['id' => $userId])->field($field)->find();
        $info = $info ? $info->toArray() : [];

        // 判断action
        if ($action == 1) {
            // 绑定
            if ($info['email']) {
                throw new BusinessException('您已经绑定邮箱,无需绑定');
            }

            // 检查邮箱重复
            $where = [['email', '=', $email], ['app_id', '=', $appId], ['id', '<>', $userId],];
            if (app(UserModel::class)->where($where)->count()) {
                throw new BusinessException('当前邮箱已绑定其他用户');
            }
        } else {
            // 解绑
            if (!$info['email']) {
                throw new BusinessException('您没有绑定邮箱,无需解绑');
            }
            if ($info['email'] != $email) {
                throw new BusinessException('您输入的邮箱非您本人邮箱');
            }
        }

        // 检查邮箱验证码
        $mailServer = new MailService();
        if (!$mailServer->checkCode($email, $verifyCode)) {
            throw new BusinessException('您的验证码不正确');
        }

        // 更新邮箱地址
        $userData = [
            'email' => $action == 1 ? $email : '',
            'is_agent' => 1,
            'whitelist' => 1,
            'update_time' => time()
        ];
        if ($action == 1 && !$info['username']) {
            $userData['username'] = $userData['email'];
        }
        $isUpdate = app(UserModel::class)->where(['id' => $userId])->save($userData);
        if (!$isUpdate) {
            throw new BusinessException('更新邮箱地址失败');
        }

        if ($action == 1) {
            // 赠送积分
            app(ScoreActivity::class)->initConfig($appId)->send($userId, 4);
        }
    }

    /**
     * changePassword
     * @param array $params
     * @throws
     */
    public function changePassword(array $params)
    {
        // 提取参数
        $userId = $params['userId'];
        $code = $params['code'];
        $appId = GlobalsVariableService::get('appId');
        $password = sha1(trim($params['password']));

        // 查询用户信息
        $field = 'openid,email';
        $info = app(UserModel::class)->where(['id' => $userId])->field($field)->find();
        $info = $info ? $info->toArray() : [];
        if (!$info) {
            throw new BusinessException('用户信息异常');
        }

        // 检查是否设置邮箱
        if (!$info['email']) {
            throw new BusinessException('请先绑定邮箱');
        }

        // 查询微信用户信息
        $wx = new WxService();
        $wx->setAppId($appId);
        $wxInfo = $wx->getUserInfoByCode($code);
        if ($wxInfo['openid'] != $info['openid']) {
            throw new BusinessException('账号绑定的微信才能设置密码');
        }

        // 更新用户密码
        $userData = [
            'password' => $password,
            'update_time' => time()
        ];
        $isUpdate = app(UserModel::class)->where(['id' => $userId])->save($userData);
        if (!$isUpdate) {
            throw new BusinessException('设置密码失败');
        }
    }


    /**
     * bindOpenid
     * @param array $params
     * @throws
     */
    public function bindOpenid(array $params)
    {
        // 提取参数
        $iv = $params['iv'] ?? '';
        $code = $params['code'];
        $userId = $params['userId'];
        $appId = getAppId();
        $encryptedData = $params['encryptedData'] ?? '';

        // 查询用户信息
        $field = 'openid,unionid,status';
        $info = app(UserModel::class)->where(['id' => $userId])->field($field)->find();
        $info = $info ? $info->toArray() : [];
        if (!$info || $info['status'] !== 1) {
            throw new BusinessException('当前账号信息不存在');
        }

        // 查询微信用户信息
        $wx = new WxService();
        $wx->setAppId($appId);
        $wxInfo = $wx->getUserInfo($code, $iv, $encryptedData);
        if (empty($wxInfo['openid'])) {
            throw new BusinessException('获取微信用户信息失败');
        }

        // 检查Openid是否重复
        $openid = $wxInfo['openid'];
        $unionid = $wxInfo['unionid'] ?? '';
        $where = [['openid', '=', $openid], ['app_id', '=', $appId], ['id', '<>', $userId],];
        if (app(UserModel::class)->where($where)->count()) {
            throw new BusinessException('当前微信已绑定其他用户');
        }
        if (!$info['openid'] || (!$info['unionid'] && $unionid)) {
            // 更新信息
            $data = [
                'openid' => $openid,
                'unionid' => $unionid,
                'update_time' => time(),
            ];
            app(UserModel::class)->where(['id' => $userId])->save($data);

            // 赠送积分
            app(ScoreActivity::class)->initConfig($appId)->send($userId, 3);
        }
    }

    /**
     * 微信登录
     * @param array $params
     * @return array
     * @throws
     */
    public function wxLogin(array $params): array
    {
        // 提取参数
        $code = $params['code'];
        $appId = GlobalsVariableService::get('appId');
        $wxPhoneCode = $params['wx_phone_code'] ?? '';

        // 查询微信用户信息
        $wx = new WxService();
        $wx->setAppId($appId);
        $wxInfo = $wx->getUserInfo($code, '', '');
        if (empty($wxInfo['openid'])) {
            throw new BusinessException('获取微信用户信息失败');
        }

        // 查询微信用户手机号
        $wxPhone = '';
        if ($wxPhoneCode) {
            $wxPhone = $wx->getUserPhoneNumber($wxPhoneCode);
        }

        // 提取参数openid查询用户
        $openid = $wxInfo['openid'];
        $unionid = $wxInfo['unionid'] ?? '';
        $field = 'id,openid,avatar,status,nickname,email,username,mobile';
        $where = [['openid', '=', $openid], ['app_id', '=', $appId]];
        $userInfo = app(UserModel::class)->where($where)->field($field)->find();

        // 如果未通过openid注册查询unionid
        if (!$userInfo && $unionid) {
            $where = [['unionid', '=', $unionid], ['app_id', '=', $appId]];
            $userInfo = app(UserModel::class)->where($where)->field($field)->find();
        }
        $userInfo = $userInfo ? $userInfo->toArray() : [];

        // 判断微信手机号是否可用
        $wxPhoneCanUse = false;
        if ($wxPhone) {
            $userService = new UserService();
            $wxPhoneCanUse = $userService->checkMobileCanBind($appId, $wxPhone, $userInfo['id'] ?? 0);
        }

        // 创建或更新用户
        if ($userInfo) {
            // 组装数据
            $data = [
                'openid' => $wxInfo['openid'],
                'unionid' => $unionid,
                'update_time' => time(),
            ];

            // 填充手机号
            if ($wxPhoneCanUse && !$userInfo['mobile']) {
                $data['mobile'] = $wxPhone;
            }

            // 更新用户
            app(UserModel::class)->where(['id' => $userInfo['id']])->save($data);

            // 赠送积分
            app(ScoreActivity::class)->initConfig($appId)->send($userInfo['id'], 2);
        } else {
            // 组装数据
            $time = time();
            $userInfo = [
                'nickname' => '没有起名字的同学',
                'username' => $openid,
                'avatar' => getRandAvatar(),
                'openid' => $openid,
                'unionid' => $unionid,
                'status' => 1,
                'app_id' => $appId,
                'create_time' => $time,
                'update_time' => $time,
            ];
            if ($wxPhoneCanUse) {
                $userInfo['mobile'] = $wxPhone;
                $userInfo['nickname'] = hideMobile($wxPhone);
            }

            // 查询上级
            $userAgentRecord = new UserAgentRecord();
            $userInfo['agent_id'] = $userAgentRecord->getMyAgentIdByOpenid($appId, $openid);

            // 创建用户
            $user_id = app(UserModel::class)->insert($userInfo, true);
            if (!$user_id) {
                throw new BusinessException('创建用户异常');
            }

            // 保存分销关系
            if ($userInfo['agent_id']) {
                $agentRelation = new AgentRelation();
                $agentRelation->add($user_id, $userInfo['agent_id']);

                // 标记白名单
                (new UserService())->setUserToWhitelist($user_id);
            }

            // 赠送积分
            app(ScoreActivity::class)->initConfig($appId)->send($user_id, 1);

            // 记录userId
            $userInfo['id'] = $user_id;
        }

        // 生成token
        $userInfo['token'] = JwtHelper::create($userInfo['id'], config('mcp.tokenExpire'));

        // 返回
        return $userInfo;
    }

    /**
     * share
     * @param $code
     * @param $agentId
     * @param $requestIp
     * @throws
     */
    public function share($appId, $code, $agentId, $requestIp)
    {
        // 查询用户信息
        $userModel = new UserModel();
        if (!$code || !$requestIp || !$userModel->checkIsExistByUid($agentId)) {
            return;
        }

        // 安全校验
        try {
            $openid = checkSafeByWxCode($appId, $code);
        } catch (BusinessException $businessException) {
            throw new BusinessException($businessException->getMessage());
        }

        // 获取活动配置
        $scoreActivity = new ScoreActivity();
        $scoreActivity->initConfig($appId);
        $sendScore = $scoreActivity->source_map[5]['score'];

        // 查询用户最新访问记录
        $userAgentRecord = new UserAgentRecord();
        $where = [['app_id', '=', $appId], ['openid', '=', $openid]];
        $userVisitRecord = $userAgentRecord->where($where)->order('create_at desc')->find();
        $userVisitRecord = $userVisitRecord ? $userVisitRecord->toArray() : [];
        $userVisitRecordCount = $userAgentRecord->where($where)->count();

        // 限制点击超过50次则不再赠送积分
        if ($userVisitRecordCount >= 50) {
            return;
        }

        // 曾经点击过的用户
        $time = time();
        if ($userVisitRecord) {
            // 限制24小时可重复点击
            $c_time = strtotime($userVisitRecord['create_at']);
            if (($time - $c_time) < 86400) {
                return;
            }
            // 曾经点击过的用户,重复点击只送200
            $sendScore = $scoreActivity->source_map[15]['score'];
        }

        // 查询用户是否注册
        $userService = new UserService();
        $userInfo = $userService->getUserByOpenid($appId, $openid);
        if ($userInfo) {
            // 自己点击不送积分
            if ($userInfo['id'] == $agentId) {
                return;
            }

            // 已经注册用户帮助点击赠送标准
            $sendScore = $scoreActivity->source_map[16]['score'];
        }

        // 只有积分大于0时才进行后续操作
        if ($sendScore > 0) {
            // 保存访问记录并赠送积分
            if ($userAgentRecord->save(
                [
                    'ip' => $requestIp,
                    'openid' => $openid,
                    'agent_id' => $agentId,
                    'app_id' => $appId,
                ]
            )) {
                // 赠送积分
                app(ScoreActivity::class)->initConfig($appId)->send($agentId, 5, $sendScore);
            }
        }
    }

    /**
     * 用户排行
     * @return mixed
     * @throws BusinessException
     */
    public function ranking(): array
    {
        // 查询排名
        $rankIngData = (new UserModel())->getUserRanking();

        // 构建返回
        $responseData = [
            'first' => [],
            'last' => [],
            'date' => date('Y-m-d'),
            'avg' => 0,
            'rate' => 0,
        ];

        // 生成平均数和排名
        foreach ($rankIngData as $key => $val) {
            $val['count'] += 700;
            if ($key == 10) {
                break;
            }
            if ($key < 3) {
                $responseData['first'][] = $val;
            } else {
                $responseData['last'][] = $val;
            }
        }
        $count = array_sum(array_column($responseData['last'] + $responseData['first'], 'count'));
        $responseData['avg'] = ceil($count / 10);

        // 生成正确率
        $cacheKey = 'user_ranking_rate';
        $rate = Cache::get($cacheKey);
        if (!$rate) {
            $rate = rand(90, 95);
            Cache::set($cacheKey, $rate, 86400);
        }
        $responseData['rate'] = $rate;

        // 返回
        return $responseData;
    }

    /**
     * scene
     * @param array $data
     */
    public function scene(array $data)
    {
        // 提取参数
        $code = $data['code'] ?? '';
        $userId = $data['userId'] ?? 0;
        $scene = $data['scene'] ?? 0;
        $appId = GlobalsVariableService::get('appId');

        // 允许的场景值
        $allowScene = ['1023'];
        if (!$code || !$userId || !$scene || !in_array($scene, $allowScene)) {
            return;
        }

        // 安全校验
        try {
            checkSafeByWxCode($appId, $code);
        } catch (BusinessException $businessException) {
            return;
        }

        // 赠送积分
        app(ScoreActivity::class)->initConfig($appId)->send($userId, 9);
    }


    /**
     * switch
     * @param array $param
     * @return array
     * @throws
     */
    public function auth(array $param): array
    {
        // 提取参数
        $authKey = $param['authKey'];

        // 查询数据
        return (new UserService())->getAuthVal($authKey);
    }


    /**
     * switch
     * @param array $param
     * @return array
     * @throws
     */
    public function switch(array $param): array
    {
        // 提取参数
        $userId = $param['userId'] ?? 0;

        // 提取H5配置
        $appId = getAppId();
        $config = app(AppConfig::class)->getByIdAndType($appId, 'h5_config');
        $authKey = (new UserService())->buildAuthKey($userId);

        // 提取安卓配置
        $androidConfig = app(AppConfig::class)->getByIdAndType($appId, 'android_config');

        // 返回
        return [
            'h5' => $config['host'] . '/#/pages/user/login/auth?authKey=' . $authKey,
            'android' => $androidConfig['downloadUrl'],
        ];
    }

    /**
     * about
     * @param array $data
     */
    public function about(array $data): array
    {
        // 提取参数
        $appId = getAppId();
        $config = app(AppConfig::class)->getByIdAndType($appId, 'about_us');
        $list = [
            [
                'icon' => 'cuIcon-infofill',
                'title' => $config['app_introduction_title'],
                'content' => $config['app_introduction_content'],
            ],
            [
                'icon' => 'cuIcon-friendaddfill',
                'title' => $config['app_cooperation_title'],
                'content' => $config['app_cooperation_content'],
            ],
            [
                'icon' => 'cuIcon-messagefill',
                'title' => $config['app_contact_title'],
                'content' => $config['app_contact_content'],
            ],
        ];
        return $list;
    }

    /**
     * bindMobile
     * @param array $param
     * @throws BusinessException
     */
    public function bindMobile(array $param)
    {
        // 提取参数
        $code = trim($param['code']);
        $mobile = trim($param['mobile']);
        $userId = $param['userId'] ?? 0;
        $appId = getAppId();

        // 检查验证码
        if (!app(SmsService::class)->checkCode($mobile, $code)) {
            throw new BusinessException('验证码不正确或已失效');
        }

        // 检查手机号
        if (app(UserService::class)->getUserByMobile($appId, $mobile)) {
            throw new BusinessException('手机号码已经被其他人绑定');
        }

        // 更新手机号
        $time = time();
        $data = [
            'mobile' => $mobile,
            'is_agent' => 1,
            'whitelist' => 1,
            'update_time' => $time,
        ];
        $where = [['id', '=', $userId]];
        $isUpdate = app(UserModel::class)->where($where)->update($data);
        if (!$isUpdate) {
            throw new BusinessException('绑定手机号码失败');
        }

        // 赠送积分
        app(ScoreActivity::class)->initConfig($appId)->send($userId, 12);
    }

    /**
     * bindWxMobile
     * @param array $param
     * @throws BusinessException
     */
    public function bindWxMobile(array $param)
    {
        // 提取参数
        $userId = $param['userId'];
        $appId = GlobalsVariableService::get('appId');
        $wxPhoneCode = $param['wx_phone_code'] ?? '';

        // 查询微信用户手机号
        $wx = new WxService();
        $wx->setAppId($appId);
        $mobile = $wx->getUserPhoneNumber($wxPhoneCode);
        if (empty($mobile)) {
            throw new BusinessException('获取微信用户手机号失败');
        }

        // 检查手机号
        if (app(UserService::class)->getUserByMobile($appId, $mobile)) {
            throw new BusinessException('手机号码已经被其他人绑定');
        }

        // 更新手机号
        $time = time();
        $data = [
            'mobile' => $mobile,
            'is_agent' => 1,
            'whitelist' => 1,
            'update_time' => $time,
        ];
        $where = [['id', '=', $userId]];
        $isUpdate = app(UserModel::class)->where($where)->update($data);
        if (!$isUpdate) {
            throw new BusinessException('绑定手机号码失败');
        }

        // 赠送积分
        app(ScoreActivity::class)->initConfig($appId)->send($userId, 12);

        // 返回
        return $mobile;
    }

    /**
     * subscribe
     * @param array $param
     * @throws BusinessException
     */
    public function subscribe(array $param)
    {
        // 提取参数
        $template_id = trim($param['template_id']);
        $status = trim($param['status']);
        $userId = $param['userId'] ?? 0;
        $appId = getAppId();

        // 查询数据
        $where = [
            ['uid', '=', $userId],
            ['template_id', '=', $template_id],
            ['app_id', '=', $appId],
        ];
        $row = app(UserSubscribe::class)->where($where)->find();

        // 新增|更新数据
        $time = time();
        if ($row) {
            $saveData = [
                'status' => $status,
                'update_time' => $time,
            ];
            app(UserSubscribe::class)->where($where)->update($saveData);
        } else {
            $saveData = [
                'app_id' => $appId,
                'template_id' => $template_id,
                'uid' => $userId,
                'status' => 1,
                'create_time' => $time,
                'update_time' => $time,
            ];
            app(UserSubscribe::class)->where($where)->insert($saveData);
        }
    }
}